package org.simpleframwork.core;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.simpleframwork.core.annotation.Component;
import org.simpleframwork.core.annotation.Controller;
import org.simpleframwork.core.annotation.Repository;
import org.simpleframwork.core.annotation.Service;
import org.simpleframwork.util.ClassUtil;
import org.simpleframwork.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {


    /**
     * 存放所有被配置标记的目标对象的map
     */
    private final ConcurrentHashMap<Class<?>, Object> beanMap = new ConcurrentHashMap<>();

    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION = Arrays.asList(Component.class, Controller.class, Repository.class, Service.class);

    /**
     * 获取bean容器实例
     * @author weiyuewen 2020/6/10 17:18
     */
    public static BeanContainer getInstance(){
        return Container.HOLDER.instance;
    }

    private enum Container{
        HOLDER;
        private BeanContainer instance;
        Container(){
            instance = new BeanContainer();
        }
    }

    /**
     * 扫描加载所有的bean
     * @author weiyuewen 2020/6/10 17:26
     */
    public synchronized void loadBeans(String packageName){
        if (isLoaded()){
            log.warn("BeanContainer has benn loaded");
            return;
        }
        Set<Class<?>> classSet = ClassUtil.extractPackageClass(packageName);
        if (ValidationUtil.isEmpty(classSet)){
            log.warn("extract noting from packageName :" + packageName);
            return;
        }
        for (Class<?> clazz : classSet){
            for (Class<? extends Annotation> annotation : BEAN_ANNOTATION){
                if (clazz.isAnnotationPresent(annotation)){
                    beanMap.put(clazz, ClassUtil.newInstance(clazz, true));
                }
            }
        }
        loaded = true;
    }


    /**
     * 添加一个class对象及其bean实例
     * @author weiyuewen 2020/6/12 10:17
     */
    public Object addBean(Class<?> clazz, Object bean) {
        return beanMap.put(clazz, bean);
    }

    /**
     * 移除一个IOC容器的对象
     * @author weiyuewen 2020/6/12 10:19
     */
    public Object removeBean(Class<?> clazz){
        return beanMap.remove(clazz);
    }

    /**
     * 根据class对象获取bean实例
     * @author weiyuewen 2020/6/12 10:20
     */
    public Object getBean(Class<?> clazz){
        return beanMap.get(clazz);
    }

    /**
     * 获取容器管理的所有class对象集合
     * @author weiyuewen 2020/6/12 10:21
     */
    public Set<Class<?>> getClasses(){
        return beanMap.keySet();
    }

    /**
     * 获取所有bean的集合
     * @author weiyuewen 2020/6/12 10:22
     */
    public Set<Object> getBeans(){
        return new HashSet<>(beanMap.values());
    }

    /**
     * 根据注解筛选出bean的class集合
     * @author weiyuewen 2020/6/12 10:23
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation){
        Set<Class<?>> keySet = getClasses();
        if (ValidationUtil.isEmpty(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz:keySet){
            if (clazz.isAnnotationPresent(annotation)){
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0 ? classSet : null;
    }

    /**
     * 通过接口或者父类获取实现类或者子类的class集合，不包括其本身
     * @author weiyuewen 2020/6/12 10:39
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass){
        Set<Class<?>> keySet = getClasses();
        if (ValidationUtil.isEmpty(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz:keySet){
            //判断是否是其父类或者接口
            if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)){
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0 ? classSet : null;
    }

    private boolean loaded = false;

    public boolean isLoaded(){
        return loaded;
    }

    /**
     * 获取bean实例数量
     * @author weiyuewen 2020/6/10 18:00
     */
    public int size(){
        return beanMap.size();
    }

}
